import {DynamicQuery, DynamicQueryOptions} from "./dynamicQuery";
import {DbClient, Transaction} from "./db/dbClient";
import {anyToEntities, anyToEntity, OrderBy, PageResponse, ParentConfig, Sql, TableConfig} from "./common";
import 'reflect-metadata';

// 定义元数据键常量
const METADATA_KEYS = {
    TABLE: 'table',
    IGNORE_FIELDS: 'ignoreField',
    PARENT_CONFIG: 'parent'
} as const;

// 定义查询条件类型
type QueryCondition = Record<string, any>;

/**
 * 实体动态查询类，用于特定实体的数据库操作
 */
export class EntityDynamicQuery<T extends object> extends DynamicQuery {
    private readonly entityClass: new () => T;
    private readonly entityFields: string[];
    private readonly parentConfigs: ParentConfig[];

    constructor(client: DbClient, entityClass: new () => T, options: DynamicQueryOptions = {}) {
        const tableName = Reflect.getMetadata(METADATA_KEYS.TABLE, entityClass.prototype);

        if (!tableName) {
            throw new Error(`Entity class ${entityClass.name} is missing @Entity decorator`);
        }

        const tableConfig = new TableConfig(tableName, []);
        super(tableConfig, client, options);

        this.entityClass = entityClass;
        this.parentConfigs = this.getMetadata(entityClass.prototype, METADATA_KEYS.PARENT_CONFIG, []);
        this.entityFields = this.getEntityFields(this.parentConfigs);

        tableConfig.columnSet = this.entityFields;
        tableConfig.parents = this.parentConfigs;
    }

    /**
     * 获取实体字段列表
     */
    private getEntityFields(parents: ParentConfig[]): string[] {
        const parentObjects = parents.map(value => value.parentObject);
        // 显式声明类型，避免推断为 never[]
        const ignoreFields: string[] = this.getMetadata(this.entityClass.prototype, METADATA_KEYS.IGNORE_FIELDS, []);
        ignoreFields.push(...parentObjects);

        return Reflect.ownKeys(new this.entityClass())
            .filter(key => typeof key === 'string' && !ignoreFields.includes(key as string)) as string[];
    }

    /**
     * 获取元数据，如果不存在则返回默认值
     */
    private getMetadata<T>(target: Object, metadataKey: string, defaultValue: T): T {
        const metadata = Reflect.getMetadata(metadataKey, target);
        return metadata !== undefined ? metadata : defaultValue;
    }

    /**
     * 将数据库结果转换为实体对象
     */
    private toEntity(data: any): T | null {
        return data ? anyToEntity(data, () => new this.entityClass()) : null;
    }

    /**
     * 将数据库结果数组转换为实体对象数组
     */
    private toEntities(data: any[]): T[] {
        return data ? anyToEntities(data, () => new this.entityClass()) : [];
    }

    /**
     * 查找所有匹配条件的实体
     */
    async findAll(query: QueryCondition = {}, transaction?: Transaction, page: OrderBy = {}): Promise<T[]> {
        const results = await super.findAll(query, transaction, page);
        return this.toEntities(results);
    }

    /**
     * 查找第一个匹配条件的实体
     */
    async findOne(query: QueryCondition = {}, transaction?: Transaction): Promise<T | null> {
        const result = await super.findOne(query, transaction);
        return this.toEntity(result);
    }

    /**
     * 分页查询实体
     */
    async find(query: QueryCondition, page: PageResponse<T>, transaction?: Transaction): Promise<void> {
        await super.find(query, page, transaction);
        page.content = this.toEntities(page.content);
    }

    /**
     * 导航分页查询实体
     */
    async navigationFind(query: QueryCondition = {}, page: PageResponse<T>, transaction?: Transaction): Promise<void> {
        await super.navigationFind(query, page, transaction);
        page.content = this.toEntities(page.content);
    }

    /**
     * 通过SQL分页查询实体
     */
    async findBySql({
                        selectSql,
                        formWhereSql,
                        orderBySql = ""
                    }: Sql, page: PageResponse<T>, transaction?: Transaction): Promise<void> {
        await super.findBySql({countInSql: null, selectSql, formWhereSql, orderBySql}, page, transaction);
        page.content = this.toEntities(page.content);
    }

    /**
     * 导航查询所有匹配条件的实体
     */
    async navigationFindAll(query: QueryCondition = {}, page?: OrderBy, transaction?: Transaction): Promise<T[]> {
        const results = await super.navigationFindAll(query, page, transaction);
        return this.toEntities(results);
    }

    /**
     * 导航查询第一个匹配条件的实体
     */
    async navigationFindOne(query: QueryCondition = {}, transaction?: Transaction): Promise<T | null> {
        const result = await super.navigationFindOne(query, transaction);
        return this.toEntity(result);
    }

    /**
     * 创建新实体
     */
    async create(data: Record<string, any> = {}, hasReturn: boolean = true, transaction?: Transaction): Promise<T | null> {
        const result = await super.create(data, hasReturn, transaction);
        return this.toEntity(result);
    }

    /**
     * 保存实体（有则更新，无则创建）
     */
    async save(data: Record<string, any> = {}, transaction?: Transaction): Promise<T | null> {
        const result = await super.save(data, transaction);
        return this.toEntity(result);
    }

    /**
     * 批量保存实体
     */
    async saveAll(entities: Record<string, any>[] = [], transaction?: Transaction): Promise<T[]> {
        const results = await super.saveAll(entities, transaction);
        return this.toEntities(results);
    }

    /**
     * 更新实体
     */
    async update(data: Record<string, any>, isAllUpdate: boolean = true, transaction?: Transaction): Promise<T | null> {
        const result = await super.update(data, isAllUpdate, transaction);
        return this.toEntity(result);
    }

    /**
     * 根据ID批量更新实体
     */
    async updateByIds(
        data: Record<string, any>,
        ids: any[] = [],
        isAllUpdate: boolean = true,
        transaction?: Transaction
    ): Promise<T[]> {
        const results = await super.updateByIds(data, ids, isAllUpdate, transaction);
        return this.toEntities(results);
    }

    /**
     * 根据查询条件更新实体并返回结果
     */
    async updateByQueryWithResult(
        data: Record<string, any>,
        query: QueryCondition,
        isAllUpdate: boolean = true,
        transaction?: Transaction
    ): Promise<T[]> {
        const results = await super.updateByQueryWithResult(data, query, isAllUpdate, transaction);
        return this.toEntities(results);
    }

    /**
     * 根据ID查找实体
     */
    async findById(id: any, transaction?: Transaction): Promise<T | null> {
        const result = await super.findById(id, transaction);
        return this.toEntity(result);
    }

    /**
     * 根据ID列表批量查找实体
     */
    async findByIds(ids: any[] = [], transaction?: Transaction): Promise<T[]> {
        const results = await super.findByIds(ids, transaction);
        return this.toEntities(results);
    }

    /**
     * 填充父对象
     */
    protected async fillParentObject(content: any[], transaction?: Transaction): Promise<void> {
        await super.fillParentObject(content, transaction);

        for (const parent of this.parentConfigs) {
            if (!parent.parentClass) continue;

            content.forEach(entity => {
                if (entity[parent.parentObject]) {
                    entity[parent.parentObject] = anyToEntity(
                        entity[parent.parentObject],
                        () => new (parent.parentClass as any)()
                    );
                }
            });
        }
    }
}

/**
 * 实体装饰器，用于标记实体类并指定对应的数据库表名
 */
export function Entity(tableName: string): ClassDecorator {
    return (target: Function) => {
        if (!tableName) {
            throw new Error('Table name is required for @Entity decorator');
        }
        Reflect.defineMetadata(METADATA_KEYS.TABLE, tableName, target.prototype);
    };
}

/**
 * 父配置参数接口
 */
interface ParentParams {
    parentId: string;
    parentClass?: new () => any;
    parentTable?: string;
    parentIdName?: string;
}

/**
 * 表字段装饰器，用于标记实体字段属性
 */
export function TableField(config: {
    ignore?: boolean,
    parentConfig?: ParentParams
} = {ignore: false}): PropertyDecorator {
    return (target, propertyKey) => {
        if (config.parentConfig) {
            setParentConfig(target, config.parentConfig, propertyKey);
        }

        const ignoreFields: (string | symbol)[] = getMetadata(target, METADATA_KEYS.IGNORE_FIELDS, []);
        ignoreFields.push(propertyKey);
        Reflect.defineMetadata(METADATA_KEYS.IGNORE_FIELDS, ignoreFields, target);
    };
}

/**
 * 父对象装饰器，用于标记实体中的父对象属性
 */
export function Parent(config: ParentParams): PropertyDecorator {
    return (target, propertyKey) => {
        setParentConfig(target, config, propertyKey);
    };
}

/**
 * 设置父对象配置元数据
 */
function setParentConfig(target: Object, config: ParentParams, propertyKey: string | symbol): void {
    const parentConfigs: ParentConfig[] = getMetadata(target, METADATA_KEYS.PARENT_CONFIG, []);

    let parentTable: string;
    let parentIdName: string;

    if (config.parentClass) {
        parentTable = Reflect.getMetadata(METADATA_KEYS.TABLE, config.parentClass.prototype);
        if (!parentTable) {
            throw new Error(`Parent class ${config.parentClass.name} is missing @Entity decorator`);
        }
        parentIdName = 'id';
    } else {
        if (!config.parentTable || !config.parentIdName) {
            throw new Error('Either parentClass or both parentTable and parentIdName must be provided');
        }
        parentTable = config.parentTable;
        parentIdName = config.parentIdName;
    }

    const parentConfig: ParentConfig = {
        parentObject: propertyKey as string,
        parentTable,
        parentIdName,
        parentId: config.parentId,
        parentClass: config.parentClass
    };

    parentConfigs.push(parentConfig);
    Reflect.defineMetadata(METADATA_KEYS.PARENT_CONFIG, parentConfigs, target);
}

/**
 * 获取元数据，如果不存在则返回默认值
 */
function getMetadata<T>(target: Object, metadataKey: string, defaultValue: T): T {
    const metadata = Reflect.getMetadata(metadataKey, target);
    return metadata !== undefined ? metadata : defaultValue;
}